{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# A slight introduction to cv and image processing with OpenCV + Bonus\n",
    "Этот туториал немного выходит за рамки открытого курса, но для коллег, решивших продолжить развиваться в области DL, computer vision, #class_cs231n введение в библиотеку OpenCV будет очень полезным.\n",
    "\n",
    "OpenCV (англ. Open Source Computer Vision Library, библиотека компьютерного зрения с открытым исходным кодом) — библиотека алгоритмов компьютерного зрения, обработки изображений и численных алгоритмов общего назначения с открытым кодом. Реализована на C/C++, также разрабатывается для Python, Java, Ruby, Matlab, Lua и других языков.\n",
    "\n",
    "В этом туториале продемонстрированно:\n",
    "\n",
    " - Как устанавливать нужные библиотеки\n",
    " - Особенности чтения изображений и вывода на экран\n",
    " - Принцип изображения простых геометрических фигур и текста на изображении\n",
    " - Различные преобразования над изображениями\n",
    " - Как читать видеопоток с файла и записывать в файл\n",
    " - Как читать видеопоток с камеры\n",
    " - Чистка изображений, фильтрация элементов изображений\n",
    " - Поиск паттернов\n",
    " - Распознавание лица и глаз при помощи каскадов Хаара\n",
    " - Bonus: распознавание лица и его элементов при помощи библиотеки dlib\n",
    "P.S. Я настоятельно рекомендую попробовать запустить этоу тетрадку у себя. Я параллельно написанию туториала сам изучаю OpenCV, с некоторыми фичами реально забавно работать (особенно бонусная часть). Надеюсь этот туториал не только принесет немного новых знаний, но и немного Вас развлечет.\n",
    "\n",
    "P.P.S. За помощь в составлении туториала отдельное спасибо [этому сайту](https://docs.opencv.org/3.0-beta/doc/tutorials/tutorials.html) и [особенно этому](https://pythonprogramming.net/)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Часть Первая"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Установка OpenCV\n",
    "\n",
    "Она же самая простая часть.\n",
    "\n",
    "Для всех систем, на которых я работал достаточно ввести команду типа **pip install opencv-python**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Часть вторая\n",
    "\n",
    "## Чтение изображений"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Первым делом импортируем opencv (cv2) и numpy\n",
    "import cv2\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "\n",
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Чтение изображений из файла происходит посредством комманды **imread('путь к изображению', флаг)**.\n",
    "\n",
    "Флаги бывают следующими:\n",
    "\n",
    " - cv2.IMREAD_COLOR - по умолчанию, чтение в цвете, но эффект прозрачности (alpha) будет удален\n",
    " - cv2.IMREAD_GRAYSCALE - чтение в градации серого\n",
    " - cv2.IMREAD_UNCHANGED - чтение цветного изображения включая alpha канал\n",
    "\n",
    "*Следует отметить, что все флаги в cv2 являются константами, их имена полностью состоят из заглавных букв. Например cv2.IMREAD_COLOR = 1. Подобных констант мы еще встретим не одну*."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "img = cv2.imread('../../img/cv2-1.jpeg',  cv2.IMREAD_COLOR)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Следует отдельно добавить, что к каждому пикселю изображения можно отдельно обратиться и изменить его значение. Например так:\n",
    "```python\n",
    "px = img[55,55]\n",
    "print(px)\n",
    "img[:55,:55] = [255,0,0]\n",
    "\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Вывод изображений\n",
    "\n",
    "\n",
    "Изображение можно вывести при помощи matplotlib и imshow. Но тут стоит быть внимательнее!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.imshow(img, interpolation='bicubic')\n",
    "plt.axis('off');"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Тут следует отдельно заметить, что цветовая схема изображения не соответствует оригиналу. Данный эффект наплюдается по причине того, что opencv читает и пишет изображения в формате BGR, следовательно для корректного изображения картинки посредством matplotlib, её необходимо преобразовать в формат RGB. Для этого используется команда cvtColor(img, флаг). Флагов очень много, проэтому советую ознакомиться с документацией или поэксперементировать."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.imshow(img_rgb, interpolation='bicubic')\n",
    "plt.axis('off');"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "Второй способ отображения - штатный, но тут тоже есть свои особенности:\n",
    "\n",
    "1. Изображение открывается в отдельном окне\n",
    "2. Для закрытия изображения нужны две функции: waitKey(time) - после нажатия любой клавиши ждет time мсек до выполнения следующей функции, destroyAllWindows() - закрывает все окна\n",
    "3. **При сипользовании Jupyter и других тетрадок ни в коем случае на закрывайте окно нажатием \"на крестик\" мышкой - это повесит ваш кернел**\n",
    "4. Сама команда: **imshow('название окна', image)**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#Выводим окно с картинкой и закрываем нажатием любой клавиши клавиатуры\n",
    "cv2.imshow('image', img)\n",
    "cv2.waitKey(0)\n",
    "cv2.destroyAllWindows()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##Сохранение изображений\n",
    "\n",
    "С сохранением изображений все очень просто и осуществляется посредством функии **imwrite**:\n",
    "```python\n",
    "cv2.imwrite('путь')\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Часть третья\n",
    "### Рисуем на изображении фигуры и пишем текст"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Эта базовая часть в последствии будет очень полезной, поэтому её освоить нужно одной из первых. Хороший пример тут\n",
    "\n",
    "В нашем распоряжении круги, прямоугольники, линии, текст, полигоны, овалы. Рассмотрим чуть подробнее часть из них:\n",
    "\n",
    " - **line**(Image, (x1, y1), (x2, y2), color, thickness, lineType), (x1, y1), (x2, y2) - координаты первой и последней точек линии\n",
    " - **rectangle**(Image, (x1, y1), (x2, y2), color, thickness, lineType, shift), (x1, y1), (x2, y2) - координаты верхнего левого и нижнего правого углов\n",
    " - **circle**(Image, (x1, y1), radius, color, thickness, lineType, shift), (x1, y1) координаты центра окружности\n",
    " - **polylines**(Image, pts, npts, ncontours, isClosed, color, thickness, lineType, shift), pts - координаты точек, isClosed - замыкание контура\n",
    " - **putText**(img, text, org, font, fontFace, fontScale, color, thickness, lineType), text - текст, org - нижний левый угол начала текста"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "draw = img\n",
    "cv2.line(draw, (300,300), (150,150), (255,255,255), 15, 5);\n",
    "cv2.rectangle(draw, (15,25), (200,150), (255,0,0), 5)\n",
    "# thickness = -1 означает полностью залить фигуру цветом\n",
    "cv2.circle(draw, (100,63), 55, (0,0,255),-1);\n",
    "pts = np.array([[10,5],[20,546],[464,131],[645,321]], np.int32)\n",
    "# ВАЖНО pts закрыть [pts] в скобки.\n",
    "cv2.polylines(draw, [pts], True, (15,154,214), 20);\n",
    "font = cv2.FONT_HERSHEY_SIMPLEX\n",
    "cv2.putText(draw, 'OpenCV', (546,154), fontFace =font, lineType =cv2.LINE_8, fontScale =5, color =(231,23,123), thickness =3);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "cv2.imshow('img', draw)\n",
    "cv2.waitKey(0)\n",
    "cv2.destroyAllWindows()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.rcParams['figure.figsize'] = 14,8\n",
    "plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB), interpolation='bicubic')\n",
    "plt.axis('off');"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Также следует заметить, что наложение геометрических фигур постоянно для картинки (draw), поэтому её нужно пересожнавать для экспериментов, иначе старые изображения останутся"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Часть четвертая\n",
    "### Чтение видео"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Для чтения видео необходимо воспользоваться функцией **VideoCapture**, которая может читать видео в двух режимах:\n",
    "\n",
    " - Чтение из файла: **cv2.VideoCapture('путь к файлу')**\n",
    " - Чтение с web-камеры: **cv2.VideoCapture(ind)**, где ind - порядковый номер желаемой камеры начиная с 0\n",
    "\n",
    "Отображать видею следует через цикл, так как оно отображается покадрово"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "cap = cv2.VideoCapture(0)\n",
    "\n",
    "while True:\n",
    "    # cap возвращает 2 параметра: ret - bool (true, если сигнал с камеры или файла постувает), frame - изображение\n",
    "    ret, frame = cap.read()\n",
    "    # Я тут решил немного поиграться и конвертировать видео в формат градации серого\n",
    "    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)\n",
    "    # Повернул изображение на 180 градусов, за это отвечает флаг - 1\n",
    "    cv2.imshow('flip frame', cv2.flip(frame, 1))\n",
    "    cv2.imshow('gray', gray)\n",
    "    cv2.imshow('frame', frame)\n",
    "    cv2.imshow('gray_flip', cv2.flip(gray, 1))\n",
    "    # ВОТ НА ЭТУ КОНСТРУКЦИЮ СТОИТ ОБРАТИТЬ ВНИМАНИЕ cv2.waitKey(1) & 0xFF - побитовая операция and \n",
    "    # (0100 and 1111 = 0100) по сути тут мы блокируем возможность получения символа с кодировкой ord() \n",
    "    # выше 255 (ето рекомендация opencv), а также обозначаем, что нажатие 'q' закроет все окна\n",
    "    # (раскладка английская иначе умрет кернел, потом мы решим эту проблему заменой на esc)\n",
    "    if cv2.waitKey(10) & 0xFF == ord('q'):\n",
    "        break\n",
    "#Не забываем высвободить видеоканал и закрыть все окна\n",
    "cap.release()\n",
    "cv2.destroyAllWindows()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Приведенная выше конструкция не подходит для чтения файлов ввиду того, что ret при работе с web-камерой почти всешда True, для работы с файлом следует немного поменять код:\n",
    "```python\n",
    "cap = cv2.VideoCapture(0)\n",
    "#Созданим заранее для запуска цикла\n",
    "ret = True\n",
    "while ret == True:\n",
    "\n",
    "    ret, frame = cap.read()\n",
    "    cv2.imshow('frame', frame)\n",
    "\n",
    "    if (ret != True) or (cv2.waitKey(10) & 0xFF == ord('q')):\n",
    "        break\n",
    "\n",
    "cap.release()\n",
    "cv2.destroyAllWindows()\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Запись видео\n",
    "Для записи видео нам необходимо две функции:\n",
    "\n",
    " - **VideoWriter_fourcc(codec) - инициализация кодека видео**\n",
    " - **VideoWriter('Адрес куда пишем', кодек, fps, разрешение)**\n",
    " \n",
    "Побробнее можно почитать [тут](https://docs.opencv.org/3.1.0/dd/d43/tutorial_py_video_display.html)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "cap = cv2.VideoCapture(0)\n",
    "fourcc = cv2.VideoWriter_fourcc(*'XVID')\n",
    "out = cv2.VideoWriter('output.avi', fourcc, 20.0, (640,480))\n",
    "\n",
    "while True:\n",
    "\n",
    "    ret, frame = cap.read()\n",
    "    # Вот тут пришем\n",
    "    out.write(frame)\n",
    "    cv2.imshow('frame', frame)\n",
    "\n",
    "    \n",
    "    if cv2.waitKey(1) & 0xFF == ord('q'):\n",
    "        break\n",
    "# не забываем высвобождать потоки ввода и вывода\n",
    "cap.release()\n",
    "out.release()\n",
    "cv2.destroyAllWindows()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Далее мы пойдем чуть веселее, меньше букв больше картинок и эффектов"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Часть пятая\n",
    "### Как логотип прикрепить к фону и сделать это более-менее красиво"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "logo = cv2.imread('../../img/cv2-2.jpg', cv2.IMREAD_COLOR)\n",
    "ground = cv2.imread('../../img/cv2-3.png', cv2.IMREAD_COLOR)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Есть два изображения: логотип EA (товарный знак и все такое), и картинка с фоном (не верьте глазам, фон гораздо больше)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.rcParams['figure.figsize'] = 18,10\n",
    "plt.subplot(121)\n",
    "plt.imshow(cv2.cvtColor(logo, cv2.COLOR_BGR2RGB))\n",
    "plt.axis('off');\n",
    "plt.subplot(122)\n",
    "plt.imshow(cv2.cvtColor(ground, cv2.COLOR_BGR2RGB))\n",
    "plt.axis('off');"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "rows, cols, channels = logo.shape\n",
    "#Указываем место размещения логотипа на фоне с учетом размера лого\n",
    "roi = ground[0:rows, 0:cols]\n",
    "logo_gray = cv2.cvtColor(logo, cv2.COLOR_BGR2GRAY)\n",
    "# Тут мы для формирования маски указываем, что нижняя граница цвета для маски 220, верхняя 255\n",
    "# (белый и близкие к нему оттенки серого)\n",
    "ret, mask = cv2.threshold(logo_gray, 220, 255, cv2.THRESH_BINARY_INV)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.rcParams['figure.figsize'] = 18,10\n",
    "plt.subplot(121)\n",
    "plt.imshow(logo)\n",
    "plt.title('Logo', fontsize=15)\n",
    "plt.axis('off');\n",
    "plt.subplot(122)\n",
    "plt.imshow(mask, cmap='gray')\n",
    "plt.title('Mask', fontsize=15)\n",
    "plt.axis('off');\n",
    "\n",
    "\n",
    "# cv2.imshow('mask', mask)\n",
    "# cv2.imshow('logo', logo)\n",
    "# cv2.waitKey(0)\n",
    "# cv2.destroyAllWindows()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Тут тонкий момент: в mask при помощи threshold() мы из рисунка выделили из лого только его бэкграунд (белые элементы оригинального лого), в mask_inv мы выделили только изображение без белого фона"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "mask_inv = cv2.bitwise_not(mask)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.rcParams['figure.figsize'] = 18,10\n",
    "plt.imshow(mask_inv, cmap='gray')\n",
    "plt.title('Mask inversed', fontsize=15)\n",
    "plt.axis('off');\n",
    "# cv2.imshow('Mask inversed', mask_inv)\n",
    "# cv2.waitKey(0)\n",
    "# cv2.destroyAllWindows()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#Посредством bitwise_and и mask_inv мы вырезаем область логотипа на фоне#Посредс \n",
    "ground_bg = cv2.bitwise_and(roi, roi, mask=mask_inv)\n",
    "logo_fg = cv2.bitwise_and(logo, logo, mask=mask)\n",
    "dst = cv2.add(ground_bg, logo_fg)\n",
    "ground[0:rows, 0:cols] = dst"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.rcParams['figure.figsize'] = 18,10\n",
    "plt.imshow(cv2.cvtColor(ground, cv2.COLOR_BGR2RGB))\n",
    "plt.title('Result', fontsize=15)\n",
    "plt.axis('off');\n",
    "\n",
    "# ground = cv2.resize(ground, (640,480))\n",
    "# cv2.imshow('add', ground)\n",
    "# cv2.waitKey(0)\n",
    "# cv2.destroyAllWindows()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Лого более высокого разрешения получилось бы лучше :-)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Часть шестая\n",
    "### Исправление затемненного изображения"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Немного продолжим работу с функциями типа **threshold()**. У нас есть абсолютно читаемый скан книжной страницы!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "bookpage = cv2.imread('../../img/cv2-4.jpg')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.rcParams['figure.figsize'] = 18,10\n",
    "plt.imshow(cv2.cvtColor(bookpage, cv2.COLOR_BGR2RGB))\n",
    "plt.title('Bookpage', fontsize=15)\n",
    "plt.axis('off');\n",
    "\n",
    "# cv2.imshow('Bookpage', bookpage)\n",
    "# cv2.waitKey(0)\n",
    "# cv2.destroyAllWindows()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "retval, threshold = cv2.threshold(bookpage, 12, 255, cv2.THRESH_BINARY)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#Попробуем применить отсев по яркости пикселей\n",
    "plt.rcParams['figure.figsize'] = 18,10\n",
    "plt.imshow(cv2.cvtColor(threshold, cv2.COLOR_BGR2RGB))\n",
    "plt.title('Threshold 12-255', fontsize=15)\n",
    "plt.axis('off');\n",
    "\n",
    "\n",
    "# cv2.imshow('Bookpage', bookpage)\n",
    "# cv2.imshow('Threshold', threshold)\n",
    "# cv2.waitKey(0)\n",
    "# cv2.destroyAllWindows()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Все еще не очень! Попробуем сделать то же самое, но для изображения, преобразованного в оттенки серого."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "grayscaled = cv2.cvtColor(bookpage, cv2.COLOR_BGR2GRAY)\n",
    "retval, threshold_gray = cv2.threshold(grayscaled, 12, 255, cv2.THRESH_BINARY)\n",
    "\n",
    "plt.rcParams['figure.figsize'] = 18,10\n",
    "plt.imshow(threshold_gray, cmap='gray')\n",
    "plt.title('Threshold_gray 12-255', fontsize=15)\n",
    "plt.axis('off');\n",
    "\n",
    "# cv2.imshow('Bookpage', bookpage)\n",
    "# cv2.imshow('Threshold', threshold)\n",
    "# cv2.imshow('Threshold Gray', threshold_gray)\n",
    "# cv2.waitKey(0)\n",
    "# cv2.destroyAllWindows()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Как видно из изображения, применение жесткой границы цветов не приносит полезного эффекта. На этот случай мы применим адаптивный фильтр adaptiveThreshold(). Подробнее [тут](https://docs.opencv.org/3.4.0/d7/d1b/group__imgproc__misc.html#ga72b913f352e4a1b1b397736707afcde3) и [здесь](https://docs.opencv.org/3.4.0/d7/d4d/tutorial_py_thresholding.html)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "gaus = cv2.adaptiveThreshold(grayscaled, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 115, 1)\n",
    "retval, otsu = cv2.threshold(grayscaled, 125, 255, cv2.THRESH_OTSU)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "grayscaledgrayscal  = cv2.cvtColor(bookpage, cv2.COLOR_BGR2GRAY)\n",
    "retval, threshold_gray = cv2.threshold(grayscaled, 12, 255, cv2.THRESH_BINARY)\n",
    "\n",
    "plt.rcParams['figure.figsize'] = 18,10\n",
    "plt.imshow(gaus, cmap='gray')\n",
    "plt.title('Результат', fontsize=15)\n",
    "plt.axis('off');\n",
    "\n",
    "# cv2.imshow('Bookpage', bookpage)\n",
    "# cv2.imshow('Threshold', threshold)\n",
    "# cv2.imshow('Threshold Gray', threshold_gray)\n",
    "# cv2.imshow('Threshold Adaptive', gaus)\n",
    "# cv2.imshow('Threshold Otsu', otsu)\n",
    "# cv2.waitKey(0)\n",
    "# cv2.destroyAllWindows()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Часть седьмая\n",
    "### Bluring\n",
    "\n",
    "\n",
    "Тут бы я посоветовал использовать камеру и что-нибуль красное"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "cap = cv2.VideoCapture(0)\n",
    "while True:\n",
    "    _, frame = cap.read()\n",
    "    # Тут необходимо преобразовать изображение в формат HSV\n",
    "    hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)\n",
    "    # Задаем границы красного цвета\n",
    "    lower_red = np.array([150,150,50])\n",
    "    apper_red = np.array([180,255,255])\n",
    "    \n",
    "    # Создаем маску\n",
    "    mask = cv2.inRange(hsv, lower_red, apper_red)\n",
    "    #Применяем маску к изображению\n",
    "    res = cv2.bitwise_and(frame, frame, mask=mask)\n",
    "    \n",
    "    \n",
    "    kernel = np.ones((15,15), np.float32)/255\n",
    "    \n",
    "    #Производим разного рода преобразования\n",
    "    smoothed = cv2.filter2D(res, -1, kernel)\n",
    "    blur = cv2.GaussianBlur(res, (15,15), 0)\n",
    "    median = cv2.medianBlur(res, 15)\n",
    "    bilateral = cv2.bilateralFilter(res, 15, 75,75)\n",
    "    \n",
    "    k = cv2.waitKey(5) & 0xFF\n",
    "    \n",
    "    cv2.imshow('frame', frame)\n",
    "    cv2.imshow('mask', mask)\n",
    "    cv2.imshow('res', res)\n",
    "    cv2.imshow('smoothed', smoothed) \n",
    "    cv2.imshow('blur', blur)\n",
    "    cv2.imshow('median', median)\n",
    "    cv2.imshow('bilateral', bilateral)\n",
    "    #Жмем esc для закрытия окон\n",
    "    if k==27:\n",
    "        break\n",
    "cv2.destroyAllWindows()\n",
    "cap.release()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Для ленивых, то же самое, но на изображении"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "in_red = cv2.imread('../../img/cv2-5.jpg')\n",
    "    \n",
    "hsv = cv2.cvtColor(in_red, cv2.COLOR_BGR2HSV)\n",
    "# Задаем границы красного цвета\n",
    "lower_red = np.array([150,150,50])\n",
    "apper_red = np.array([180,255,255])\n",
    "    \n",
    "# Создаем маску\n",
    "mask = cv2.inRange(hsv, lower_red, apper_red)\n",
    "#Применяем маску к изображению\n",
    "res = cv2.bitwise_and(in_red, in_red, mask=mask)\n",
    "    \n",
    "    \n",
    "kernel = np.ones((15,15), np.float32)/255\n",
    "    \n",
    "#Производим разного рода преобразования\n",
    "smoothed = cv2.filter2D(res, -1, kernel)\n",
    "blur = cv2.GaussianBlur(res, (15,15), 0)\n",
    "median = cv2.medianBlur(res, 15)\n",
    "bilateral = cv2.bilateralFilter(res, 15, 75,75)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.rcParams['figure.figsize'] = 18,10\n",
    "plt.subplot(321)\n",
    "plt.imshow(cv2.cvtColor(in_red, cv2.COLOR_BGR2RGB))\n",
    "plt.title('Original', fontsize=15)\n",
    "plt.axis('off');\n",
    "plt.subplot(322)\n",
    "plt.imshow(cv2.cvtColor(res, cv2.COLOR_BGR2RGB))\n",
    "plt.title('res', fontsize=15)\n",
    "plt.axis('off');\n",
    "plt.subplot(323)\n",
    "plt.imshow(cv2.cvtColor(smoothed, cv2.COLOR_BGR2RGB))\n",
    "plt.title('smoothed', fontsize=15)\n",
    "plt.axis('off');\n",
    "plt.subplot(324)\n",
    "plt.imshow(cv2.cvtColor(blur, cv2.COLOR_BGR2RGB))\n",
    "plt.title('blur', fontsize=15)\n",
    "plt.axis('off');\n",
    "plt.subplot(325)\n",
    "plt.imshow(cv2.cvtColor(median, cv2.COLOR_BGR2RGB))\n",
    "plt.title('median', fontsize=15)\n",
    "plt.axis('off');\n",
    "plt.subplot(326)\n",
    "plt.imshow(cv2.cvtColor(bilateral, cv2.COLOR_BGR2RGB))\n",
    "plt.title('bilateral', fontsize=15)\n",
    "plt.axis('off');"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Denoising\n",
    "Смягчение шума с камеры. Осень позоже на предыдущте действия. Тут опять лучше с камерой"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "cap = cv2.VideoCapture(0)\n",
    "while True:\n",
    "    _, frame = cap.read()\n",
    "    hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)\n",
    "    \n",
    "    lower_red = np.array([150,150,50])\n",
    "    apper_red = np.array([180,255,255])\n",
    "    \n",
    "    mask = cv2.inRange(hsv, lower_red, apper_red)\n",
    "    \n",
    "    res = cv2.bitwise_and(frame, frame, mask=mask)\n",
    "    \n",
    "    kernel = np.array((5,5), np.uint8) \n",
    "    erosion = cv2.erode(mask, kernel, iterations=1)\n",
    "    dilation = cv2.dilate(mask, kernel, iterations=1)\n",
    "    \n",
    "    opening = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)\n",
    "    closing = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)\n",
    " \n",
    "\n",
    "   \n",
    "    cv2.imshow('frame', frame)\n",
    "    cv2.imshow('res', res)\n",
    "    cv2.imshow('erosion', erosion)\n",
    "    cv2.imshow('dilation', dilation)\n",
    "    cv2.imshow('opening', opening)\n",
    "    cv2.imshow('closing', closing)\n",
    "    \n",
    "    k = cv2.waitKey(5) & 0xFF\n",
    "    if k==27:\n",
    "        break\n",
    "cv2.destroyAllWindows()\n",
    "cap.release()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Ленивым!)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "hsv = cv2.cvtColor(in_red, cv2.COLOR_BGR2HSV)\n",
    "\n",
    "lower_red = np.array([150,150,50])\n",
    "apper_red = np.array([180,255,255])\n",
    "    \n",
    "mask = cv2.inRange(hsv, lower_red, apper_red)\n",
    "    \n",
    "res = cv2.bitwise_and(in_red, in_red, mask=mask)\n",
    "    \n",
    "kernel = np.array((5,5), np.uint8) \n",
    "erosion = cv2.erode(mask, kernel, iterations=1)\n",
    "dilation = cv2.dilate(mask, kernel, iterations=1)\n",
    "    \n",
    "opening = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)\n",
    "closing = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.rcParams['figure.figsize'] = 18,10\n",
    "plt.subplot(321)\n",
    "plt.imshow(cv2.cvtColor(in_red, cv2.COLOR_BGR2RGB))\n",
    "plt.title('Original', fontsize=15)\n",
    "plt.axis('off');\n",
    "plt.subplot(322)\n",
    "plt.imshow(cv2.cvtColor(res, cv2.COLOR_BGR2RGB))\n",
    "plt.title('res', fontsize=15)\n",
    "plt.axis('off');\n",
    "plt.subplot(323)\n",
    "plt.imshow(erosion, cmap='gray')\n",
    "plt.title('erosion', fontsize=15)\n",
    "plt.axis('off');\n",
    "plt.subplot(324)\n",
    "plt.imshow(dilation, cmap='gray')\n",
    "plt.title('dilation', fontsize=15)\n",
    "plt.axis('off');\n",
    "plt.subplot(325)\n",
    "plt.imshow(opening, cmap='gray')\n",
    "plt.title('opening', fontsize=15)\n",
    "plt.axis('off');\n",
    "plt.subplot(326)\n",
    "plt.imshow(closing, cmap='gray')\n",
    "plt.title('closing', fontsize=15)\n",
    "plt.axis('off');"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Часть восьмая\n",
    "### Распознавание границ\n",
    "Довольно часто при работе с изображениями есть необходимость убрать лишнюю информацию для упрощения обучения сетей: цвета, некоторая детализация объектов. Для этих целей прекрасно подходит встроенный в OpenCV алгоритм Canny\n",
    "\n",
    " - Canny(Image, minVal, maxVal), где minVal, maxVal - параметры алгоритма [за подробностями сюда](https://docs.opencv.org/3.1.0/da/d22/tutorial_py_canny.html)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "cap = cv2.VideoCapture(0)\n",
    "while True:\n",
    "    _, frame = cap.read()\n",
    "\n",
    "    edges = cv2.Canny(frame, 200,200)\n",
    "    cv2.imshow('Edges', edges)\n",
    "    k = cv2.waitKey(5) & 0xFF\n",
    "    # Чтобы закрыть окно нажмите Esc\n",
    "    if k==27:\n",
    "        break\n",
    "cv2.destroyAllWindows()\n",
    "cap.release()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "car = cv2.imread('../../img/cv2-6.jpg')\n",
    "edges = cv2.Canny(car, 200,300)\n",
    "\n",
    "plt.rcParams['figure.figsize'] = 18,10\n",
    "plt.subplot(121)\n",
    "plt.imshow(cv2.cvtColor(car, cv2.COLOR_BGR2RGB))\n",
    "plt.title('Original', fontsize=15)\n",
    "plt.axis('off');\n",
    "plt.subplot(122)\n",
    "plt.imshow(edges, cmap='gray')\n",
    "plt.title('Canny', fontsize=15)\n",
    "plt.axis('off');"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Часть девятая\n",
    "### Поиск по шаблону\n",
    "Довольно часто стоит задача поиска объектов по шаблону. Для этого будет полезной функция **matchTemplate()**\n",
    "\n",
    " - matchTemplate(Image, Template, flag)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#Загружаем изображение\n",
    "img_bgr = cv2.imread('../../img/cv2-7.jpg')\n",
    "img_gray = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2GRAY)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.rcParams['figure.figsize'] = 18,10\n",
    "plt.imshow(cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB))\n",
    "plt.title('Image', fontsize=15)\n",
    "plt.axis('off');"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Грузим шаблон для поиска# Грузим \n",
    "template = cv2.imread('../../img/cv2-8.jpg', 0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.rcParams['figure.figsize'] = 1,1\n",
    "plt.imshow(template, cmap='gray')\n",
    "plt.title('Template', fontsize=15)\n",
    "plt.axis('off');"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "w, h = template.shape[::-1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#Ищем похожие объекты\n",
    "res = cv2.matchTemplate(img_gray, template, cv2.TM_CCOEFF_NORMED)\n",
    "# Ставим границу ссответствия\n",
    "threshold = 0.78\n",
    "#Поиск индексов похожих объектов\n",
    "loc = np.where(res >= threshold)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#Тут пригодятся знания, про прорисовку прямоугольников#Тут при \n",
    "for pt in zip(*loc[::-1]):\n",
    "    cv2.rectangle(img_bgr, pt, (pt[0]+w, pt[1]+h), (0,255,255), 2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.rcParams['figure.figsize'] = 18,10\n",
    "plt.imshow(cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB))\n",
    "plt.title('Image', fontsize=15)\n",
    "plt.axis('off');\n",
    "\n",
    "# cv2.imshow('detected', img_bgr)\n",
    "# cv2.waitKey(0)\n",
    "# cv2.destroyAllWindows()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Не идеально, но уже что-то"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Часть десятая\n",
    "### Сопоставление элементов\n",
    "В OpenCV осуществлена возможность сопоставления элементов одинаковых объектов на различных картинках"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "img1 = cv2.imread('../../img/cv2-9.jpg', 0)\n",
    "img2 = cv2.imread('../../img/cv2-10.jpg', 0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "orb = cv2.ORB_create()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "kp1, des1 = orb.detectAndCompute(img1, None)\n",
    "kp2, des2 = orb.detectAndCompute(img2, None)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck = True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "matches = bf.match(des1, des2)\n",
    "matches = sorted(matches, key = lambda x: x.distance)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# matches[:10] означает, что нас интересует 10 элементов\n",
    "img3 = cv2.drawMatches(img1, kp1, img2, kp2, matches[:10], None, flags = 2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.rcParams['figure.figsize'] = 18,10\n",
    "plt.imshow(cv2.cvtColor(img3, cv2.COLOR_BGR2RGB))\n",
    "plt.title('Image', fontsize=15)\n",
    "plt.axis('off');\n",
    "\n",
    "# cv2.imshow('Corners', img3)\n",
    "# cv2.waitKey(0)\n",
    "# cv2.destroyAllWindows()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Самое интересное!!!\n",
    "## Определение лица и глаз при помощи каскадов Хаара"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Каскады Хаара - довольно древняя методика выявдения фич из изображения, но все еще работает. Для выполнения этой части туториала необходимо пройти [сюда](https://github.com/opencv/opencv/tree/master/data/haarcascades) и скачать 2 файла **'haarcascade_frontalface_default.xml'** и **'haarcascade_eye.xml'**. \n",
    "  Причем скачать не кликнув правой клавишей мыши, а нажать на файл, кликнуть по опции raw и только потом созранить .xml\n",
    "<img src=\"../../img/cv2-11.png\">\n",
    "\n",
    "\n",
    "Лучше используйте камеру!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')\n",
    "eye_cascade = cv2.CascadeClassifier('haarcascade_eye.xml')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "cap = cv2.VideoCapture(0)\n",
    "while True:\n",
    "    ret, img = cap.read()\n",
    "    gray  = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)\n",
    "    faces = face_cascade.detectMultiScale(gray, 1.3, 5)\n",
    "    for (x, y, w, h) in faces:\n",
    "        cv2.rectangle(img, (x, y), (x+w, y+h), (255,0,0),2)\n",
    "        roi_gray = gray[y:y+h, x:x+w]\n",
    "        roi_color = img[y:y+h, x:x+w]\n",
    "        eyes = eye_cascade.detectMultiScale(roi_gray, 1.3, 5)\n",
    "        for (ex, ey, ew, eh) in eyes:\n",
    "            cv2.rectangle(roi_color, (ex, ey), (ex + ew, ey + eh), (0,255,0), 2)\n",
    "            \n",
    "    cv2.imshow('img', img)\n",
    "    k = cv2.waitKey(30) & 0xff\n",
    "    if k == 27:\n",
    "        break\n",
    "        \n",
    "cap.release()\n",
    "cv2.destroyAllWindows()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Далее для просмотра"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "img = cv2.imread('../../img/cv2-12.jpg')\n",
    "gray  = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)\n",
    "#Ищем лица\n",
    "faces = face_cascade.detectMultiScale(gray, 1.3, 5)\n",
    "#Мы хотим искать глаза внутри лица\n",
    "for (x, y, w, h) in faces:\n",
    "    cv2.rectangle(img, (x, y), (x+w, y+h), (255,0,0),2)\n",
    "    roi_gray = gray[y:y+h, x:x+w]\n",
    "    roi_color = img[y:y+h, x:x+w]\n",
    "    eyes = eye_cascade.detectMultiScale(roi_gray, 1.3, 5)\n",
    "    for (ex, ey, ew, eh) in eyes:\n",
    "        cv2.rectangle(roi_color, (ex, ey), (ex + ew, ey + eh), (0,255,0), 2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.rcParams['figure.figsize'] = 18,10\n",
    "plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))\n",
    "plt.title('Image', fontsize=15)\n",
    "plt.axis('off');"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Вроде бы все хорошо, но работает не достаточно хорошо!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "img = cv2.imread('../../img/cv2-13.jpg')\n",
    "gray  = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)\n",
    "#Ищем лица\n",
    "faces = face_cascade.detectMultiScale(gray, 1.3, 5)\n",
    "#Мы хотим искать глаза внутри лица\n",
    "for (x, y, w, h) in faces:\n",
    "    cv2.rectangle(img, (x, y), (x+w, y+h), (255,0,0),2)\n",
    "    roi_gray = gray[y:y+h, x:x+w]\n",
    "    roi_color = img[y:y+h, x:x+w]\n",
    "    eyes = eye_cascade.detectMultiScale(roi_gray, 1.3, 5)\n",
    "    for (ex, ey, ew, eh) in eyes:\n",
    "        cv2.rectangle(roi_color, (ex, ey), (ex + ew, ey + eh), (0,255,0), 2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.rcParams['figure.figsize'] = 18,10\n",
    "plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))\n",
    "plt.title('Image', fontsize=15)\n",
    "plt.axis('off');"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "В общем не совсем то! Поэтому я предлагаю попробовать воспользоваться библиотекой, основанной на нейронных сетях **dlib**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# BONUS DLIB\n",
    "Для установки пользователям *nix систем лучше воспользоваться [репозиторием](https://github.com/davisking/dlib), устанавливается по инструкции без проблем, правда перед компиляцией нужно поставить libx11-dev (sudo apt-get install libx11-dev).\n",
    "\n",
    "С пользователями Windows не все так просто, компилировать не советую ни в коем случае, лучше установите **dlib-19.8.1-cp36-cp36m-win_amd64.whl** [отсюда](https://pypi.org/simple/dlib/), потом *pip install dlib-19.8.1-cp36-cp36m-win_amd64.whl*\n",
    "\n",
    "Также надо будет скачать вот этот [файл](http://dlib.net/files/shape_predictor_68_face_landmarks.dat.bz2) и разархивировать его, потом он будет использоваться в dlib.shape_predictor\n",
    "\n",
    "И последнее... Надо установить *imutils* (pip install imutils)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import dlib\n",
    "import imutils\n",
    "from imutils import face_utils"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def rect_to_bb(rect):\n",
    "    #Принимает на вход объект dlib, содержащий координаты лиц и возвращает кортеж\n",
    "    x = rect.left()\n",
    "    y = rect.top()\n",
    "    w = rect.right() - x\n",
    "    h = rect.bottom() - y\n",
    "\n",
    "\n",
    "    return (x, y, w, h)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def shape_to_np(shape, dtype=\"int\"):\n",
    "\n",
    "    # возвращает координаты элементов лица\n",
    "    coords = np.zeros((68, 2), dtype=dtype)\n",
    "    for i in range(0, 68):\n",
    "        coords[i] = (shape.part(i).x, shape.part(i).y)\n",
    "\n",
    "    return coords"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "detector = dlib.get_frontal_face_detector()\n",
    "predictor = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Обязательно пробовать с камерой"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "cap = cv2.VideoCapture(0)\n",
    "# fourcc = cv2.VideoWriter_fourcc(*'XVID')\n",
    "# out = cv2.VideoWriter('output.avi',fourcc, 10.0, (640,480))\n",
    "while True:\n",
    "    ret, img = cap.read()\n",
    "    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)\n",
    "    dets = detector(gray, 1)\n",
    "    for (i, rect) in enumerate(dets):\n",
    "\n",
    "        shape = predictor(img, rect)\n",
    "        shape = face_utils.shape_to_np(shape)\n",
    "\n",
    "        # Очертание лица\n",
    "        (x, y, w, h) = face_utils.rect_to_bb(rect)\n",
    "        cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)\n",
    "\n",
    "        # Нумировка лица\n",
    "        cv2.putText(img, \"Face #{}\".format(i + 1), (x - 10, y - 10),\n",
    "            cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)\n",
    "\n",
    "        #Прорисовка элементов лица\n",
    "        for (x, y) in shape:\n",
    "            cv2.circle(img, (x, y), 2, (0, 0, 255), -1)\n",
    "\n",
    "    cv2.imshow('img', img)\n",
    "    k = cv2.waitKey(30) & 0xff\n",
    "    if k == 27:\n",
    "        break\n",
    "cap.release()\n",
    "# out.release()\n",
    "cv2.destroyAllWindows()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "img = cv2.imread('../../img/cv2-12.jpg')\n",
    "gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)\n",
    "dets = detector(gray, 1)\n",
    "for (i, rect) in enumerate(dets):\n",
    "\n",
    "    shape = predictor(img, rect)\n",
    "    shape = face_utils.shape_to_np(shape)\n",
    "    # Очертание лица\n",
    "    (x, y, w, h) = face_utils.rect_to_bb(rect)\n",
    "    cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)\n",
    "\n",
    "    # Нумировка лица\n",
    "    cv2.putText(img, \"Face #{}\".format(i + 1), (x - 10, y - 10),\n",
    "        cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)\n",
    "\n",
    "    #Прорисовка элементов лица\n",
    "    for (x, y) in shape:\n",
    "        cv2.circle(img, (x, y), 2, (0, 0, 255), -1)\n",
    "\n",
    "plt.rcParams['figure.figsize'] = 18,10\n",
    "plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))\n",
    "plt.title('Image', fontsize=15)\n",
    "plt.axis('off');"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Так уже лучше, проверим несколько лиц"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "img = cv2.imread('../../img/cv2-13.jpg')\n",
    "gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)\n",
    "dets = detector(gray, 1)\n",
    "for (i, rect) in enumerate(dets):\n",
    "\n",
    "    shape = predictor(img, rect)\n",
    "    shape = face_utils.shape_to_np(shape)\n",
    "    # Очертание лица\n",
    "    (x, y, w, h) = face_utils.rect_to_bb(rect)\n",
    "    cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)\n",
    "\n",
    "    # Нумировка лица\n",
    "    cv2.putText(img, \"Face #{}\".format(i + 1), (x - 10, y - 10),\n",
    "        cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)\n",
    "\n",
    "    #Прорисовка элементов лица\n",
    "    for (x, y) in shape:\n",
    "        cv2.circle(img, (x, y), 2, (0, 0, 255), -1)\n",
    "\n",
    "plt.rcParams['figure.figsize'] = 18,10\n",
    "plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))\n",
    "plt.title('Image', fontsize=15)\n",
    "plt.axis('off');"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Тоже работает хорошо! Но можно сделать интереснее: точки на лице имеют определенную нумирацию.\n",
    "<img src=\"../../img/cv2-14.jpg\">\n",
    "\n",
    "Следовательно можно сделать еще так!! + закомментил строки записи видео с определением лица"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Опять начинаем с камеры"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "cap = cv2.VideoCapture(0)\n",
    "# fourcc = cv2.VideoWriter_fourcc(*'XVID')\n",
    "# out = cv2.VideoWriter('output.avi',fourcc, 10.0, (640,480))\n",
    "while True:\n",
    "    ret, img = cap.read()\n",
    "    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)\n",
    "    dets = detector(gray, 1)\n",
    "    for (i, rect) in enumerate(dets):\n",
    "  \n",
    "        shape = predictor(img, rect)\n",
    "        shape = face_utils.shape_to_np(shape)\n",
    "\n",
    "\n",
    "        (x, y, w, h) = face_utils.rect_to_bb(rect)\n",
    "        cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)\n",
    "\n",
    "\n",
    "        cv2.putText(img, \"Face #{}\".format(i + 1), (x - 10, y - 10),\n",
    "            cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)\n",
    "\n",
    "\n",
    "        for i,  (x, y) in enumerate(shape):\n",
    "            if i < 16:\n",
    "                cv2.circle(img, (x, y), 2, (0, 0, 255), -1)\n",
    "            elif i>=17 and i < 27:\n",
    "                cv2.circle(img, (x, y), 2, (0, 255, 0), -1)\n",
    "            elif i >= 27 and i < 36:\n",
    "                cv2.circle(img, (x, y), 2, (255, 0, 0), -1)  \n",
    "            elif i>=36 and i < 48:\n",
    "                cv2.circle(img, (x, y), 2, (16, 255, 255), -1) \n",
    "            else:\n",
    "                cv2.circle(img, (x, y), 2, (135, 11, 189), -1)\n",
    "#     out.write(img)\n",
    "    cv2.imshow('img', img)\n",
    "    k = cv2.waitKey(5) & 0xff\n",
    "    if k == 27:\n",
    "        break\n",
    "cap.release()\n",
    "# out.release()\n",
    "cv2.destroyAllWindows()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "На картинках"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "img = cv2.imread('../../img/cv2-12.jpg')\n",
    "gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)\n",
    "dets = detector(gray, 1)\n",
    "for (i, rect) in enumerate(dets):\n",
    "\n",
    "    shape = predictor(img, rect)\n",
    "    shape = face_utils.shape_to_np(shape)\n",
    "    # Очертание лица\n",
    "    (x, y, w, h) = face_utils.rect_to_bb(rect)\n",
    "    cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)\n",
    "\n",
    "    # Нумировка лица\n",
    "    cv2.putText(img, \"Face #{}\".format(i + 1), (x - 10, y - 10),\n",
    "        cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)\n",
    "\n",
    "    #Прорисовка элементов лица + задаем цвет для каждого элемента\n",
    "    for i,  (x, y) in enumerate(shape):\n",
    "        if i < 16:\n",
    "            cv2.circle(img, (x, y), 2, (0, 0, 255), -1)\n",
    "        elif i>=17 and i < 27:\n",
    "            cv2.circle(img, (x, y), 2, (0, 255, 0), -1)\n",
    "        elif i >= 27 and i < 36:\n",
    "            cv2.circle(img, (x, y), 2, (255, 0, 0), -1)  \n",
    "        elif i>=36 and i < 48:\n",
    "            cv2.circle(img, (x, y), 2, (16, 255, 255), -1) \n",
    "        else:\n",
    "            cv2.circle(img, (x, y), 2, (135, 11, 189), -1)\n",
    "\n",
    "plt.rcParams['figure.figsize'] = 18,10\n",
    "plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))\n",
    "plt.title('Image', fontsize=15)\n",
    "plt.axis('off');"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "img = cv2.imread('../../img/cv2-13.jpg')\n",
    "gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)\n",
    "dets = detector(gray, 1)\n",
    "for (i, rect) in enumerate(dets):\n",
    "\n",
    "    shape = predictor(img, rect)\n",
    "    shape = face_utils.shape_to_np(shape)\n",
    "    # Очертание лица\n",
    "    (x, y, w, h) = face_utils.rect_to_bb(rect)\n",
    "    cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)\n",
    "\n",
    "    # Нумировка лица\n",
    "    cv2.putText(img, \"Face #{}\".format(i + 1), (x - 10, y - 10),\n",
    "        cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)\n",
    "\n",
    "    #Прорисовка элементов лица + задаем цвет для каждого элемента\n",
    "    for i,  (x, y) in enumerate(shape):\n",
    "        if i < 16:\n",
    "            cv2.circle(img, (x, y), 2, (0, 0, 255), -1)\n",
    "        elif i>=17 and i < 27:\n",
    "            cv2.circle(img, (x, y), 2, (0, 255, 0), -1)\n",
    "        elif i >= 27 and i < 36:\n",
    "            cv2.circle(img, (x, y), 2, (255, 0, 0), -1)  \n",
    "        elif i>=36 and i < 48:\n",
    "            cv2.circle(img, (x, y), 2, (16, 255, 255), -1) \n",
    "        else:\n",
    "            cv2.circle(img, (x, y), 2, (135, 11, 189), -1)\n",
    "\n",
    "plt.rcParams['figure.figsize'] = 18,10\n",
    "plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))\n",
    "plt.title('Image', fontsize=15)\n",
    "plt.axis('off');"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Гифка!!!!!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<img src=\"https://habrastorage.org/webt/-z/ha/ba/-zhabappcnh9pvoyvddgrpkdhho.gif\">"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Все! Дошедшим до конца - Спасибо! Надеюсь Вам понравился туториал!"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
